通过数据转换管道释放 Scikit-learn 预处理的强大功能。 学习如何构建稳健高效的机器学习工作流程,以实现最佳模型性能。
Scikit-learn 预处理:掌握用于机器学习的数据转换管道
在机器学习领域,数据的质量直接影响模型的性能。 原始数据通常包含不一致性、缺失值和不同的比例,使其不适合直接使用。 Scikit-learn 是一个强大的 Python 库,提供了一套全面的预处理技术,可将数据转换为适合机器学习算法的格式。 本文深入探讨 Scikit-learn 预处理的世界,重点介绍数据转换管道的创建和利用,以简化您的机器学习工作流程。
为什么数据预处理至关重要
数据预处理是清理、转换和组织原始数据的过程,使其更适合机器学习模型。 这是一个至关重要的步骤,因为机器学习算法对输入特征的规模和分布很敏感。 如果没有适当的预处理,模型可能会表现不佳,从而导致不准确的预测和不可靠的结果。 以下是数据预处理至关重要的一些关键原因:
- 提高模型性能: 经过预处理的数据使模型能够更有效地学习并获得更高的准确性。
- 处理缺失值: 估算技术填充缺失的数据点,防止算法崩溃或产生有偏差的结果。
- 标准化特征比例: 缩放方法确保所有特征对模型贡献相同,防止具有较大值的特征主导学习过程。
- 编码分类变量: 编码技术将分类数据转换为机器学习算法可以理解的数值表示。
- 减少噪声和异常值: 预处理可以帮助减轻异常值和噪声数据的影响,从而产生更强大的模型。
Scikit-learn 管道简介
Scikit-learn 管道提供了一种将多个数据转换步骤链接在一起,形成一个可重用的对象的方法。 这简化了您的代码,提高了可读性,并防止了模型评估期间的数据泄漏。 管道本质上是一系列数据转换,后跟一个最终估计器(例如,分类器或回归器)。 以下是管道如此有益的原因:
- 代码组织: 管道将整个数据预处理和建模工作流程封装到一个单元中,使您的代码更有条理且更易于维护。
- 防止数据泄漏: 管道确保数据转换一致地应用于训练和测试数据,防止数据泄漏,这可能导致过度拟合和泛化不良。
- 简化模型评估: 管道可以更轻松地使用交叉验证等技术评估模型的性能,因为整个预处理和建模工作流程一致地应用于每个折叠。
- 简化部署: 管道可以轻松部署到生产环境,确保数据以与训练期间相同的方式进行预处理。
Scikit-learn 中常用的数据预处理技术
Scikit-learn 提供了广泛的预处理技术。 以下是一些最常用的:
1. 缩放和标准化
缩放和标准化是用于将数值特征转换为相似值范围的技术。 这很重要,因为具有不同比例的特征可能会不成比例地影响学习过程。 Scikit-learn 提供了几种缩放和标准化方法:
- StandardScaler: 通过删除平均值并缩放到单位方差来标准化特征。 这是一种广泛使用的技术,它假设数据遵循正态分布。
公式:
x_scaled = (x - mean) / standard_deviation示例: 假设您有美元的房价和平方英尺。 缩放这些特征可确保模型不会过度重视具有较大值的特征(例如,房价)。
- MinMaxScaler: 将特征缩放到指定的范围,通常在 0 到 1 之间。 当您要保留数据的原始分布时,这非常有用。
公式:
x_scaled = (x - min) / (max - min)示例: 图像处理通常使用 MinMaxScaler 将像素值标准化到 [0, 1] 范围。
- RobustScaler: 使用对异常值具有鲁棒性的统计量(例如,中位数和四分位距 (IQR))来缩放特征。 当您的数据包含异常值时,这是一个不错的选择。
公式:
x_scaled = (x - median) / IQR示例: 在金融数据集中,异常值很常见(例如,极端的股市波动),RobustScaler 可以提供更稳定的结果。
- Normalizer: 单独将样本标准化为单位范数。 当特征向量的大小比单个特征值更重要时,这非常有用。
公式(L2 范数):
x_scaled = x / ||x||示例: 在文本处理中,标准化术语频率-逆文档频率 (TF-IDF) 向量是一种常见的做法。
2. 编码分类变量
机器学习算法通常需要数值输入,因此需要将分类变量转换为数值表示。 Scikit-learn 提供了几种编码技术:
- OneHotEncoder: 为特征中的每个类别创建二进制列。 这适用于名义分类特征(没有内在顺序的特征)。
示例: 编码一个具有诸如“美国”、“加拿大”和“英国”之类的值的“国家”特征将创建三个新列:“country_USA”、“country_Canada”和“country_UK”。
- OrdinalEncoder: 根据每个类别的顺序为其分配一个整数值。 这适用于有序分类特征(具有有意义的顺序的特征)。
示例: 编码一个具有诸如“高中”、“学士”和“硕士”之类的值的“教育程度”特征将分别分配诸如 0、1 和 2 之类的整数值。
- LabelEncoder: 使用 0 到 n_classes-1 之间的值编码目标标签。 使用此方法对分类问题中的目标变量进行编码。
示例: 将“垃圾邮件”和“非垃圾邮件”标签分别编码为 0 和 1。
- TargetEncoder(需要 category_encoders 库): 根据每个类别的目标变量的平均值对分类特征进行编码。 如果在交叉验证设置中没有小心使用,可能会导致目标泄漏。
3. 处理缺失值
缺失值是真实世界数据集中常见的问题。 Scikit-learn 提供了估算(填充)缺失值的技术:
- SimpleImputer: 使用常量值、平均值、中位数或特征的最频繁值来估算缺失值。
- KNNImputer: 使用 k 最近邻算法来估算缺失值。 它找到 k 个与具有缺失值的样本最接近的样本,并使用这些邻居的平均值来估算缺失值。
- IterativeImputer: 使用迭代建模方法来估算缺失值。 每个具有缺失值的特征都被建模为其他特征的函数,并且缺失值被迭代预测。
4. 特征转换
特征转换涉及从现有特征创建新特征。 这可以通过捕获非线性关系或特征之间的交互来提高模型性能。 一些技术包括:
- PolynomialFeatures: 生成特征的多项式组合。 例如,如果您有两个特征 x1 和 x2,则 PolynomialFeatures 可以创建诸如 x1^2、x2^2、x1*x2 之类的新特征。
- FunctionTransformer: 将自定义函数应用于特征。 这允许您执行任意转换,例如对数转换或指数转换。
- PowerTransformer: 应用幂转换使数据更像高斯分布。 这对于假设正态性的算法(例如,线性回归)可能很有用。 (包括 Box-Cox 和 Yeo-Johnson 转换)
使用 Scikit-learn 构建数据转换管道
现在,让我们通过构建数据转换管道将这些预处理技术付诸实践。 以下是分步指南:
1. 导入必要的库
首先从 Scikit-learn 导入所需的库:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder, SimpleImputer
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
import pandas as pd
2. 加载并准备您的数据
使用 pandas 或任何其他合适的方法加载您的数据集。 识别数据集中的数值和分类特征。 例如:
data = {
'age': [25, 30, 35, 40, 45, None],
'country': ['USA', 'Canada', 'USA', 'UK', 'Canada', 'USA'],
'salary': [50000, 60000, 70000, 80000, 90000, 55000],
'purchased': [0, 1, 0, 1, 0, 1]
}
df = pd.DataFrame(data)
3. 定义预处理步骤
创建您要使用的预处理转换器的实例。 例如,要处理数值特征,您可以使用 StandardScaler 和 SimpleImputer。 对于分类特征,您可以使用 OneHotEncoder。 考虑在缩放或编码之前包含处理缺失值的策略。
numerical_features = ['age', 'salary']
categorical_features = ['country']
numerical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='mean')),
('scaler', StandardScaler())
])
categorical_transformer = Pipeline(steps=[
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
4. 创建 ColumnTransformer
使用 ColumnTransformer 将不同的转换器应用于数据的不同列。 这允许您分别预处理数值和分类特征。
preprocessor = ColumnTransformer(
transformers=[
('num', numerical_transformer, numerical_features),
('cat', categorical_transformer, categorical_features)
])
5. 构建管道
创建一个 Pipeline 对象,该对象将预处理步骤与机器学习模型链接在一起。 这确保在将数据馈送到模型之前对其进行一致的预处理。
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', LogisticRegression())])
6. 训练和评估模型
将您的数据分为训练集和测试集。 然后,在训练数据上训练管道,并在测试数据上评估其性能。
X = df.drop('purchased', axis=1)
y = df['purchased']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
pipeline.fit(X_train, y_train)
score = pipeline.score(X_test, y_test)
print(f'Model accuracy: {score}')
完整示例代码
这是构建和训练数据转换管道的完整代码:
import pandas as pd
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder, SimpleImputer
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
# Sample Data
data = {
'age': [25, 30, 35, 40, 45, None],
'country': ['USA', 'Canada', 'USA', 'UK', 'Canada', 'USA'],
'salary': [50000, 60000, 70000, 80000, 90000, 55000],
'purchased': [0, 1, 0, 1, 0, 1]
}
df = pd.DataFrame(data)
# Define features
numerical_features = ['age', 'salary']
categorical_features = ['country']
# Create transformers
numerical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='mean')),
('scaler', StandardScaler())
])
categorical_transformer = Pipeline(steps=[
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
# Create preprocessor
preprocessor = ColumnTransformer(
transformers=[
('num', numerical_transformer, numerical_features),
('cat', categorical_transformer, categorical_features)
])
# Create pipeline
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', LogisticRegression())])
# Split data
X = df.drop('purchased', axis=1)
y = df['purchased']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Train model
pipeline.fit(X_train, y_train)
# Evaluate model
score = pipeline.score(X_test, y_test)
print(f'Model accuracy: {score}')
高级管道技术
一旦您熟悉了基础知识,您就可以探索更高级的管道技术:
1. 自定义转换器
您可以创建自己的自定义转换器来执行 Scikit-learn 中不可用的特定数据转换。 要创建自定义转换器,您需要从 TransformerMixin 和 BaseEstimator 类继承,并实现 fit 和 transform 方法。 这对于特征工程或特定领域的转换非常有用。 记住包含适当的文档字符串以提高可读性。
2. 特征联合
FeatureUnion 允许您将多个转换器的输出组合成单个特征向量。 当您要将不同的转换应用于相同的特征或组合以不同方式转换的特征时,这非常有用。 FeatureUnion 类用于将多个转换器的输出组合成单个特征向量。
3. 带有管道的网格搜索
您可以使用 GridSearchCV 来优化管道的超参数,包括预处理步骤的超参数。 这允许您自动找到预处理技术和模型参数的最佳组合。 请注意增加的计算成本。
数据预处理管道的最佳实践
以下是在构建数据预处理管道时要记住的一些最佳实践:
- 了解您的数据: 在应用任何预处理技术之前,请花时间了解您的数据。 探索特征的分布,识别缺失值,并寻找异常值。
- 记录您的管道: 在您的代码中添加注释以解释管道的每个步骤。 这将使您更容易理解和维护您的代码。
- 测试您的管道: 彻底测试您的管道以确保其正常工作。 使用单元测试来验证管道的每个步骤都在产生预期的输出。
- 避免数据泄漏: 在预处理您的数据时,请注意避免数据泄漏。 确保您仅使用来自训练数据的信息来预处理训练数据。 使用管道来确保训练数据和测试数据之间的一致性。
- 监控性能: 随着时间的推移监控模型的性能,并在需要时重新训练它。 数据分布可能会随着时间的推移而变化,因此定期重新评估您的管道并在必要时进行调整非常重要。
真实世界的例子
让我们探讨一些真实世界的例子,说明如何在不同的行业中使用数据转换管道:
- 金融: 在信用风险建模中,管道可用于预处理客户数据,包括诸如收入和信用评分之类的数值特征,以及诸如就业状况和贷款目的之类的分类特征。 可以使用诸如平均值估算或 k 最近邻估算之类的技术来估算缺失值。 缩放对于确保具有不同比例的特征不会主导模型至关重要。
- 医疗保健: 在医疗诊断中,管道可用于预处理患者数据,包括诸如年龄、血压和胆固醇水平之类的数值特征,以及诸如性别和病史之类的分类特征。 可以使用独热编码将分类特征转换为数值表示。
- 电子商务: 在产品推荐系统中,管道可用于预处理客户和产品数据,包括诸如购买频率和产品评级之类的数值特征,以及诸如产品类别和客户人口统计之类的分类特征。 管道可以包括用于文本预处理的步骤,例如分词和词干提取,以从产品描述和客户评论中提取特征。
- 制造业: 在预测性维护中,管道可用于预处理来自机器的传感器数据,包括诸如温度、压力和振动之类的数值特征,以及诸如机器类型和运行状况之类的分类特征。 由于存在异常读数的可能性,RobustScaler 在这里特别有用。
解决全球数据集中的挑战
在使用全球数据集时,您通常会遇到一些在预处理过程中需要仔细考虑的特定挑战。 以下是一些常见问题以及解决它们的策略:
- 不同的数据格式: 日期、数字和货币在不同地区可能具有不同的格式。 确保一致的解析和格式设置。 例如,日期可能是 DD/MM/YYYY 或 MM/DD/YYYY 格式。 使用适当的库来处理日期转换和格式设置。
- 语言差异: 文本数据可能使用不同的语言,这需要翻译或特定于语言的预处理技术。 考虑使用 Google Translate API(需要适当的用法注意事项和成本影响)进行翻译,或使用 NLTK 进行特定于语言的文本处理。
- 货币转换: 财务数据可能使用不同的货币。 使用最新的汇率将所有值转换为通用货币。 使用可靠的 API 获取准确的实时汇率。
- 时区: 时间序列数据可能在不同的时区中记录。 将所有时间戳转换为通用时区(例如,UTC)以确保一致性。 使用诸如 pytz 之类的库来处理时区转换。
- 文化差异: 文化差异会影响数据解释。 例如,客户满意度得分在不同的文化中可能会有不同的解释。 请注意这些差异,并在设计预处理步骤时考虑它们。
- 数据质量问题: 不同来源的数据质量可能会有很大差异。 实施强大的数据验证和清理程序以识别和纠正错误。
结论
数据预处理是机器学习管道中的一个关键步骤。 通过使用 Scikit-learn 管道,您可以简化工作流程、防止数据泄漏并提高模型的性能。 掌握这些技术将使您能够为各种应用构建更强大、更可靠的机器学习解决方案。 记住根据数据的具体特征和机器学习模型的要求来调整预处理步骤。 尝试不同的技术,找到适合您特定问题的最佳组合。 通过投入时间进行适当的数据预处理,您可以释放机器学习算法的全部潜力并获得卓越的结果。